package com.common.fileupload.upload.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.common.fileupload.config.S3UploaderConfig;
import com.common.fileupload.domain.FileModel;
import com.common.fileupload.upload.S3FileUploader;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;


/**
 * 阿里oss实现
 *
 * @author Tango
 * @since 2022/6/27
 */
@ConditionalOnProperty(name = "upload.impl", havingValue = "ali")
@Component
@Slf4j
public class AliOssUploader implements S3FileUploader<OSS> {
    @Autowired
    private S3UploaderConfig uploadConfig;

    @Override
    public OSS getClient() {
        return uploadConfig.getClient(OSS.class,
                config -> new OSSClientBuilder()
                        .build(config.getEndPoint(), config.getAccessKey(), config.getSecretKey()));
    }

    @Override
    public FileModel put(InputStream inputStream, String prefix, String fileName, String contentType, Long fileSize) {
        try {
            String fileId = UUID.randomUUID().toString();
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            String objectName = fileId + suffix;
            if (StringUtils.isNotBlank(prefix)) {
                objectName = prefix + "/" + objectName;
            }
            ObjectMetadata objectMetadata = new ObjectMetadata();

            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
            contentType = String.valueOf(ContentType.create(contentType, StandardCharsets.UTF_8.name()));
            objectMetadata.setContentType(contentType);
            objectMetadata.setUserMetadata(ImmutableMap.of(
                    FILE_ID_KEY, fileId,
                    FILE_NAME_KEY, fileName,
                    FILE_SUFFIX_KEY, suffix,
                    CONTENT_TYPE_KEY, contentType));
            PutObjectRequest putObjectRequest = new PutObjectRequest(uploadConfig.getBucketName(), objectName, inputStream, objectMetadata);
            OSS client = this.getClient();
            client.putObject(putObjectRequest);
            return new FileModel()
                    .setId(fileId)
                    .setOriginName(fileName)
                    .setObjectName(fileName)
                    .setSuffix(suffix)
                    .setContentType(contentType)
                    .setSize(fileSize)
                    .setPath(objectName)
                    .setPrefix(uploadConfig.getPrefix())
                    .setUrl(uploadConfig.getUrl(objectName))
                    .setCrAt(new Date());
        } catch (UnsupportedEncodingException e) {
            log.error("上传图片错误. e=", e);
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 获取文件
     *
     * @param filePath 文件名
     * @return FileModel
     */
    @Override
    public FileModel peek(String filePath) {
        try {
            OSSObject ossObject = getClient().getObject(uploadConfig.getBucketName(), filePath);
            ObjectMetadata objectMetadata = ossObject.getObjectMetadata();
            long contentLength = objectMetadata.getContentLength();
            String fileId = objectMetadata.getUserMetadata().get(FILE_ID_KEY);
            String fileName = objectMetadata.getUserMetadata().get(FILE_NAME_KEY);
            fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8.name());
            String contentType = objectMetadata.getContentType();
            Date crAt = objectMetadata.getLastModified();
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            return new FileModel()
                    .setId(fileId)
                    .setOriginName(fileName)
                    .setObjectName(filePath)
                    .setSuffix(suffix)
                    .setSize(contentLength)
                    .setContentType(contentType)
                    .setPath(filePath)
                    .setPrefix(uploadConfig.getPrefix())
                    .setUrl(uploadConfig.getUrl(filePath))
                    .setCrAt(Date.from(crAt.toInstant()));
        } catch (UnsupportedEncodingException e) {
            log.error("获取文件异常. e=", e);
            throw new IllegalArgumentException(e);
        }
    }


    public List<FileModel> list(String prefix) {
        ListObjectsRequest request = new ListObjectsRequest();
        request.setBucketName(uploadConfig.getBucketName());
        request.setPrefix(prefix);
        ObjectListing objectListing = getClient().listObjects(request);
        return objectListing.getObjectSummaries().stream()
                .map(item -> new FileModel()
                        .setObjectName(item.getKey())
                        .setSize(item.getSize())
                        .setPath(item.getKey())
                        .setPrefix(uploadConfig.getPrefix())
                        .setUrl(uploadConfig.getUrl(item.getKey()))
                        .setCrAt(Date.from(item.getLastModified().toInstant())))
                .filter(model -> model.getSize() > 0)
                .collect(Collectors.toList());
    }


    /**
     * 下载文件
     */
    @Override
    public InputStream get(String filePath) {
        OSSObject ossObject = getClient().getObject(uploadConfig.getBucketName(), filePath);
        return ossObject.getObjectContent();
    }
}
